package com.conversationboard.model;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

import com.conversationboard.cache.IThreadCache;
import com.conversationboard.cache.ThreadCache;
import com.conversationboard.config.Configuration;
import com.conversationboard.database.Database;
import com.conversationboard.database.Queries;
import com.conversationboard.model.adminlog.AdminLog;

public final class Message {

	private int messageId;
	private int threadId;
	private int boardId;
	private boolean deleted;
	private Date timestamp;
	private String userId;
	private String displayName;
	private String body;
	private String ipAddress;
	private Thread parentThread;
	private int arrayIndex;


	/* Move back a page size and get the message at this point. Use its ID to determine the link to the previous page of posts */

	public int getPreviousPageMessageId() throws SQLException {

		Thread thread = this.getParentThread();
		int previousPageIndex = this.arrayIndex - (Configuration.getInstance().getOldestMessageCount() - 10);

		if (previousPageIndex < 0) {
			previousPageIndex = 0;
		}

		Message message = thread.getMessages().get(previousPageIndex);

		return message.getMessageId();
	}


	public int getArrayIndex() {
		return arrayIndex;
	}


	public void setArrayIndex(int arrayIndex) {
		this.arrayIndex = arrayIndex;
	}


	public boolean isQuestion() throws SQLException {

		if (this.messageId == this.getParentThread().getFirstMessage().getMessageId()) {
			return true;
		} else {
			return false;
		}
	}


	public Message(Thread parentThread) {
		this.parentThread = parentThread;
	}


	public Thread getParentThread() {
		return parentThread;
	}


	/**
	 * Again, need all the board, thread and message for efficiency's sake, the
	 * database has a clustered index on all three.
	 * 
	 * @param boardId the board
	 * @param threadId the thread
	 * @param messageId the message
	 */

	public static void delete(User user, int boardId, int threadId, int messageId) throws SQLException {

		Connection connection = Database.getConnection();
		connection.setAutoCommit(false);

		try {

			/* Delete the message in the database */

			PreparedStatement statement = connection.prepareStatement(Queries.ADMIN_DELETE_MESSAGE);
			statement.setInt(1, boardId);
			statement.setInt(2, threadId);
			statement.setInt(3, messageId);

			statement.executeUpdate();

			/* Get the message from the cache and delete it */

			IThreadCache cache = ThreadCache.getInstance();
			Thread thread = (Thread) cache.get(boardId, threadId);

			Message message = thread.getMessage(messageId);
			message.setDeleted(true);

			AdminLog.getInstance().write(connection, user, boardId, "Message: " + messageId + " from thread: <strong>" + thread.getTitle() + "</strong> has been deleted.");

			connection.commit();

		} catch (SQLException e) {
			connection.rollback();
			throw e;
		} finally {
			Database.close(connection);
		}
	}


	public static void undelete(User user, int boardId, int threadId, int messageId) throws SQLException {

		Connection connection = Database.getConnection();
		connection.setAutoCommit(false);

		try {
			PreparedStatement statement = connection.prepareStatement(Queries.ADMIN_UNDELETE_MESSAGE);
			statement.setInt(1, boardId);
			statement.setInt(2, threadId);
			statement.setInt(3, messageId);

			statement.executeUpdate();

			/* Get the message from the cache and undelete it */

			IThreadCache cache = ThreadCache.getInstance();
			Thread thread = (Thread) cache.get(boardId, threadId);

			Message message = thread.getMessage(messageId);
			message.setDeleted(false);

			AdminLog.getInstance().write(connection, user, boardId, "Message: " + messageId + " from thread: <strong>" + thread.getTitle() + "</strong> has been undeleted.");

			connection.commit();

		} catch (SQLException e) {
			connection.rollback();
			throw e;

		} finally {
			Database.close(connection);
		}
	}


	public static void edit(User user, Message message) throws SQLException {

		Connection connection = Database.getConnection();
		connection.setAutoCommit(false);

		try {
			PreparedStatement statement = connection.prepareStatement(Queries.ADMIN_UPDATE_MESSAGE);
			statement.setString(1, message.getBody());
			statement.setInt(2, message.getBoardId());
			statement.setInt(3, message.getThreadId());
			statement.setInt(4, message.getMessageId());

			statement.executeUpdate();

			AdminLog.getInstance().write(connection, user, message.getBoardId(), "<strong>Message edited to </strong>: " + message.getBody());

			connection.commit();

		} catch (SQLException e) {
			connection.rollback();
			throw e;
		} finally {
			Database.close(connection);
		}
	}


	public String getIpAddress() {
		return ipAddress;
	}


	public void setIpAddress(String ipAddress) {
		this.ipAddress = ipAddress;
	}


	public int getMessageId() {
		return messageId;
	}


	public void setMessageId(int messageId) {
		this.messageId = messageId;
	}


	public String getDisplayName() {
		return displayName;
	}


	public void setDisplayName(String displayName) {
		this.displayName = displayName;
	}


	public int getBoardId() {
		return boardId;
	}


	public void setBoardId(int boardId) {
		this.boardId = boardId;
	}


	public String getBody() {
		return body;
	}


	public void setBody(String body) {
		this.body = body;
	}


	public int getThreadId() {
		return threadId;
	}


	public void setThreadId(int threadId) {
		this.threadId = threadId;
	}


	public Date getTimestamp() {
		return timestamp;
	}


	public void setTimestamp(Date timestamp) {
		this.timestamp = timestamp;
	}


	public String getUserId() {
		return userId;
	}


	public void setUserId(String userId) {
		this.userId = userId;
	}


	/**
	 * If the message has been deleted, or the thread that contains the message
	 * has been deleted, then return true.
	 * 
	 * @return if the message has been deleted or not.
	 */

	public boolean isDeleted() {

		if (this.getParentThread().isDeleted() || this.deleted) {
			return true;
		} else {
			return false;
		}
	}


	public void setDeleted(boolean deleted) {
		this.deleted = deleted;
	}

}
